﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Fast.Framework.Interfaces;
using Fast.Framework.Extensions;
using Fast.Framework.Models;

namespace Fast.Framework
{

    /// <summary>
    /// 删除实现类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TDbOptions"></typeparam>
    public class Delete<T, TDbOptions> : IDelete<T, TDbOptions> where T : class where TDbOptions : DbOptions
    {

        /// <summary>
        /// Ado
        /// </summary>
        private readonly IAdo<TDbOptions> ado;

        /// <summary>
        /// 删除建造者
        /// </summary>
        public IDeleteBuilder DeleteBuilder { get; }

        /// <summary>
        /// Sql表达式选项
        /// </summary>
        private readonly SqlExpressionOptions sqlExpressionOptions;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="ado">ado</param>
        /// <param name="deleteBuilder">删除建造者</param>
        public Delete(IAdo<TDbOptions> ado, IDeleteBuilder deleteBuilder)
        {
            this.ado = ado;
            DeleteBuilder = deleteBuilder;
            sqlExpressionOptions = new SqlExpressionOptions()
            {
                IgnoreParameterExpression = true,
                DbType = ado.DbOptions.DbType
            };
        }

        /// <summary>
        /// 作为
        /// </summary>
        /// <param name="tableName">表名称</param>
        /// <returns></returns>
        public IDelete<T, TDbOptions> As(string tableName)
        {
            DeleteBuilder.TableName = DbSymbolMapper.identify[ado.DbOptions.DbType].Insert(1, tableName);
            return this;
        }

        /// <summary>
        /// 条件
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <returns></returns>
        public IDelete<T, TDbOptions> Where(Expression<Func<T, bool>> expression)
        {
            var sqlInfo = expression.ResolveSql(sqlExpressionOptions);
            DeleteBuilder.Where.Add(sqlInfo.WhereFormat());
            DeleteBuilder.Parameters.Append(sqlInfo.SqlParameters);
            return this;
        }

        /// <summary>
        /// In条件
        /// </summary>
        /// <typeparam name="FieldsType">字段类型</typeparam>
        /// <param name="inFieldsName">In字段名称</param>
        /// <param name="values">值</param>
        /// <returns></returns>
        public IDelete<T, TDbOptions> In<FieldsType>(string inFieldsName, params FieldsType[] values)
        {
            return In(inFieldsName, values.ToList());
        }

        /// <summary>
        /// In条件
        /// </summary>
        /// <typeparam name="FieldsType">字段类型</typeparam>
        /// <param name="inFieldsName">In字段名称</param>
        /// <param name="values">值</param>
        /// <returns></returns>
        public IDelete<T, TDbOptions> In<FieldsType>(string inFieldsName, List<FieldsType> values)
        {
            var type = typeof(FieldsType);
            var sqlParameters = new Dictionary<string, FieldsType>().AddIdentityKey(values.ToList(), DeleteBuilder.Parameters.Count);
            DeleteBuilder.Where.Add($"{DbSymbolMapper.identify[ado.DbOptions.DbType].Insert(1, inFieldsName)} IN ({string.Join(",", sqlParameters.Keys.Select(s => $"{DbSymbolMapper.parameter[ado.DbOptions.DbType]}{s}"))})");
            DeleteBuilder.Parameters.Append(sqlParameters);
            return this;
        }

        /// <summary>
        /// In条件
        /// </summary>
        /// <typeparam name="FieldsType">字段类型</typeparam>
        /// <param name="expression">表达式</param>
        /// <param name="values">值</param>
        /// <returns></returns>
        public IDelete<T, TDbOptions> In<FieldsType>(Expression<Func<T, object>> expression, List<FieldsType> values)
        {
            var sqlInfo = expression.ResolveSql(sqlExpressionOptions);
            var sqlParameters = new Dictionary<string, FieldsType>().AddIdentityKey(values, DeleteBuilder.Parameters.Count);
            DeleteBuilder.Where.Add(sqlInfo.InFormat(DbSymbolMapper.parameter[ado.DbOptions.DbType], sqlParameters));
            DeleteBuilder.Parameters.Append(sqlParameters);
            return this;
        }

        /// <summary>
        /// NotIn条件
        /// </summary>
        /// <typeparam name="FieldsType">字段类型</typeparam>
        /// <param name="notInFieldsName">Not In字段名称</param>
        /// <param name="values">值</param>
        /// <returns></returns>
        public IDelete<T, TDbOptions> NotIn<FieldsType>(string notInFieldsName, params FieldsType[] values)
        {
            return In(notInFieldsName, values.ToList());
        }

        /// <summary>
        /// NotIn条件
        /// </summary>
        /// <typeparam name="FieldsType">字段类型</typeparam>
        /// <param name="notInFieldsName">Not In字段名称</param>
        /// <param name="values">值</param>
        /// <returns></returns>
        public IDelete<T, TDbOptions> NotIn<FieldsType>(string notInFieldsName, List<FieldsType> values)
        {
            var type = typeof(FieldsType);
            var sqlParameters = new Dictionary<string, FieldsType>().AddIdentityKey(values.ToList(), DeleteBuilder.Parameters.Count);
            DeleteBuilder.Where.Add($"{DbSymbolMapper.identify[ado.DbOptions.DbType].Insert(1, notInFieldsName)} NOT IN ({string.Join(",", sqlParameters.Keys.Select(s => $"{DbSymbolMapper.parameter[ado.DbOptions.DbType]}{s}"))})");
            DeleteBuilder.Parameters.Append(sqlParameters);
            return this;
        }

        /// <summary>
        /// NotIn条件
        /// </summary>
        /// <typeparam name="FieldsType">字段类型</typeparam>
        /// <param name="expression">表达式</param>
        /// <param name="values">值</param>
        /// <returns></returns>
        public IDelete<T, TDbOptions> NotIn<FieldsType>(Expression<Func<T, object>> expression, List<FieldsType> values)
        {
            var sqlInfo = expression.ResolveSql(sqlExpressionOptions);
            var sqlParameters = new Dictionary<string, FieldsType>().AddIdentityKey(values, DeleteBuilder.Parameters.Count);
            DeleteBuilder.Where.Add(sqlInfo.NotInFormat(DbSymbolMapper.parameter[ado.DbOptions.DbType], sqlParameters));
            DeleteBuilder.Parameters.Append(sqlParameters);
            return this;
        }

        /// <summary>
        /// 执行异步
        /// </summary>
        /// <returns></returns>
        public Task<int> ExecuteAsync()
        {
            return ado.ExecuteNonQueryAsync(this.ToString(), ado.SqlParametersBuild(DeleteBuilder.Parameters));
        }

        /// <summary>
        /// 到字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return DeleteBuilder.ToString();
        }
    }
}
